"use strict";
// 需求：对已经开发好的项目中的任何一个类，创建实例时，
// 打印日志信息
// 输出哪一个类被创建了，并输出传递了哪些参数信息
let __extends = (function (Son, Parent) {
    function getStaticExtendsWithForIn(Son, Parent) {
      for (let key in Parent) {
        if (Object.prototype.hasOwnProperty.call(Parent, key)) {
          Son[key] = Parent[key]
        }
      }
    }
  
    function getStaticExtendsWithObjectKeys(Son, Parent) {
      Object.keys(Parent).forEach(key => {
        Son[key] = Parent[key]
      })
    }
  
    function getStaticExtendsWithProto(Son, Parent) {
      Son.__proto__ = Parent;
    }
  
    let MyextendsStatic = function (Son, Parent) {
      let MyextendsStatic = Object.setPrototypeOf || getStaticExtendsWithForIn || getStaticExtendsWithObjectKeys || getStaticExtendsWithProto
      return MyextendsStatic(Son, Parent)
    }
  
    return function (Son, Parent) {
      MyextendsStatic(Son, Parent)
      function Middle() {
        this.constructor = Son;
      }
      if (Parent) {  // 如果不为空，如果父类存在
        Middle.prototype = Parent.prototype
        Son.prototype = new Middle()
      } else {  // 如果父类不存在
        Son.prototype = Object.create(null)
      }
      console.log("Object.create(null):", Object.create(null))
    }
}())
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    // argsnum 参数个数
    var argsnum = arguments.length
    // targetinfo 被装饰器修饰的目标
    // argsnum=2 装饰器修饰的是类或者构造器参数，targetinof=target[类名]
    // argsnum=4 装饰器修饰的是方法【第四个参数desc等于null】targetinfo=该方法的数据属性【desc = Object.getOwnPropertyDescriptor(target, key)】
    // argsnum=3 装饰器修饰的是方法参数或属性，targetinfo=undefined
    var targetinfo = argsnum < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc;  // s100
    // decorator保存装饰器数组元素
    var decorator;
    // 元数据信息，支持reflect-metadata元数据
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
      targetinfo = Reflect.decorate(decorators, target, key, desc);
    } else {
      // 装饰器循环，倒着循环，说明同一个目标上有多个装饰器，执行循环是倒着执行
      for (var i = decorators.length -1; i >=0; i--) {
        // 如果参数小于3【decorator为类装饰器或者构造器参数装饰器】执行decorator(targetinof)直接执行decorator装饰器，并传递目标targetinfo，这里是类
        //如果参数大于3【decorator为方法装饰器】 直接执行 decorator(target, key, targetinfo)
     //如果参数等于3【decorator为方法参数装饰器或者属性装饰器】，直接执行decorator(target,key)
     //targetinfo最终为各个装饰器执行后的返回值，但如果没有返回值，直接返回第s100行的targetinfo
        targetinfo = (argsnum < 3 ? decorator(targetinfo) : argsnum > 3 ?
            decorator(target, key, targetinfo) : decorator(target, key)) || targetinfo;
        console.log("targetinforesult:", targetinfo)
      }
    }
    return argsnum > 3 && targetinfo && Object.defineProperty(target, key, targetinfo), targetinfo;
}
Object.defineProperty(exports, "__esModule", { value: true });
// 泛型工厂类继承装饰器的好处：
// 被装饰的类，实际接收的是它的子类，可以在子类中添加特有的属性与方法。方便类的实力在任何时候调用。而传统的类装饰器，只在装饰上去时，才会触发一次的。
function LoggerInfoDecorator(param) {
    // 为什么要定义一个构造函数类型的泛型T
    // 因为如果targetClass为any类型，则LoggerSonClass类继承的是any类型，与目标类Test不兼容
    // 类装饰器底层中 Test = decorator(targetinfo) || targetinfo，而decorator就是LoggerInfoDecorator闭包函数。
    // 所以闭包返回的类，必须是目标类(Test)的兼容类型。
    // 所以方法参数定义为继承了通用构造函数类型的泛型T，因为泛型是定义时不确定类型，调用时（使用时）确定类型的语法机制。
    return function Decorator(targetClass) {
        var LoggerSonClass = /** @class */ (function (_super) {
            __extends(LoggerSonClass, _super);
            function LoggerSonClass() {
                var args = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    args[_i] = arguments[_i];
                }
                var _this = _super.apply(this, args) || this;
                console.log("日志信息......targetClass: ", targetClass.name);
                return _this;
            }
            LoggerSonClass.prototype.saySonClass = function () {
                console.log("我是子类：", LoggerSonClass.name);
            };
            return LoggerSonClass;
        }(targetClass));
        return LoggerSonClass;
    };
}
// 2.目标类
var Test = /** @class */ (function () {
    function Test(name) {
        this.name = name;
    }
    Test.prototype.eat = function () {
        console.log(this.name, "吃饭");
    };
    Test = __decorate([
        LoggerInfoDecorator(Test)
    ], Test);
    return Test;
}());
var test = new Test("张三"); // 日志信息......targetClass:  Test
test.saySonClass();
